import axios, {
  AxiosError,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
  Method,
} from 'axios';
import apis from './apis';
import globalRequestErrorHandlers from './request/error-handlers/index.global';
import globalRequestInterceptors from './request/interceptors/index.global';
import globalResponseErrorHandlers from './response/error-handlers/index.global';
import globalResponseInterceptors from './response/interceptors/index.global';

export type RequestInterceptor = (
  request: InternalAxiosRequestConfig
) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
export type ResponseInterceptor = (
  response: AxiosResponse
) => AxiosResponse | Promise<AxiosResponse>;
export type ErrorHandler = (error: AxiosError) => void;

const instance = axios.create({
  // baseURL: import.meta.env.VITE_API_URL,
  baseURL: "https://act.724vpn.com",
  timeout: 20000,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
  },
});

/**
 * Basic Request攔截器
 * @param {Array} interceptors
 * @param {Array} errorHandler
 */
const requestInterceptor = (
  interceptors: RequestInterceptor[],
  errorHandler: ErrorHandler[]
) => {
  instance.interceptors.request.use(
    async function onBeforeSend(request) {
      for (const interceptor of interceptors) {
        request = await interceptor(request);
      }
      return request;
    },
    function onError(error) {
      if (errorHandler.length > 0)
        errorHandler.forEach((handler) => handler(error));
      return Promise.reject(error);
    }
  );
};

/**
 * Basic Response攔截器
 * @param {Array} interceptors
 * @param {Array} errorHandlers
 */
const responseInterceptor = (
  interceptors: ResponseInterceptor[],
  errorHandlers: ErrorHandler[]
) => {
  instance.interceptors.response.use(
    async function onAfterReceived(response) {
      for (const interceptor of interceptors) {
        response = await interceptor(response);
      }
      return response;
    },
    function onError(error) {
      if (errorHandlers.length > 0)
        errorHandlers.forEach((handler) => handler(error));
      return Promise.reject(error);
    }
  );
};

/** 載入全域執行攔截器 */
requestInterceptor(globalRequestInterceptors, globalRequestErrorHandlers);
responseInterceptor(globalResponseInterceptors, globalResponseErrorHandlers);

/**
 * @description 封裝Axios的HTTP請求
 * @tutorial https://axios-http.com/docs/config_defaults
 * @param { String } method 請求方法
 * @param { String } url 請求路徑
 * @param { Object } data 請求參數
 * @param { Object } config 請求設定
 * @returns
 */
export function http<T>(
  method: Method,
  url: string,
  data?: any,
  config?: AxiosRequestConfig<null> | undefined
) {
  try {
    switch (method.toUpperCase()) {
      case 'GET':
        return instance.get(url, { params: data, ...config }) as Promise<T>;
      case 'POST':
        return instance.post(url, data, config) as Promise<T>;
      case 'PUT':
        return instance.put(url, data, config) as Promise<T>;
      case 'DELETE':
        return instance.delete(url, { params: data, ...config }) as Promise<T>;
      case 'PATCH':
        return instance.patch(url, data, config) as Promise<T>;
      default:
        throw new Error(`未知的 Method: ${method}`);
    }
  } catch (e) {
    console.error(e);
    throw new Error(`未知的 Method: ${e}`);
  }
}

/**
 * @description 提供外部注入Request攔截器
 * @param {Function} interceptor
 * @param {Function} handler
 */
export function onRequestInterceptor(
  interceptor: RequestInterceptor,
  handler: ErrorHandler
) {
  requestInterceptor([interceptor], [handler]);
}

/**
 * @description 提供外部注入Response攔截器
 * @param {Function} interceptor
 * @param {Function} handler
 */
export function onResponseInterceptor(
  interceptor: ResponseInterceptor,
  handler: ErrorHandler
) {
  responseInterceptor([interceptor], [handler]);
}

/**
 * API modules
 */
export default apis;
// const API = Object.freeze(
//   mapValues(apis, (mod, modName) =>
//     Object.freeze(
//       mapValues(mod, (conf: { method: Method, url: string, config?: AxiosRequestConfig<null> | undefined }, confName: string) => {
//         if (!conf.method) {
//           console.warn(`API module ${modName}.${confName} have no 'method' field, it's required.`)
//         }

//         if (!conf.url) {
//           console.warn(`API module ${modName}.${confName} have no 'url' field, it's required.`)
//         }
//         return ({ data = null, config = {} } = {}) => {
//           const combineConfig = { ...conf.config, ...config }
//           return http(conf.method, conf.url, data, combineConfig)
//         }
//       }),
//     ),
//   ),
// )

// export default API
